#!/usr/bin/env python3
"""
专注的全面测试套件
测试核心功能点：图表类型、过滤器、聚合、分段等
"""

import json
import time
import requests
from datetime import datetime
import random
from typing import Dict, List, Any


class FocusedComprehensiveTest:
    def __init__(self):
        self.base_url = "http://localhost:5000"
        self.test_cases = []
        self.results = []
        
    def generate_core_test_cases(self):
        """生成核心测试用例"""
        print("生成核心测试用例...")
        
        # 1. 图表类型测试
        chart_types = ["bar", "line", "pie", "doughnut", "polarArea", "radar"]
        for chart_type in chart_types:
            self.test_cases.append({
                "name": f"图表类型_{chart_type}",
                "chart_type": chart_type,
                "x_field": "symbol",
                "y_field": "net_profit",
                "x_aggregation": "count",
                "y_aggregation": "sum",
                "filters": [],
                "expected_result": {
                    "type": "chart_type_test",
                    "chart_type": chart_type,
                    "should_have_data": True
                }
            })
        
        # 2. 过滤器测试
        filter_tests = [
            {
                "name": "品种过滤_MESM25",
                "filters": [{"field": "symbol", "operator": "equals", "value": "MESM25", "logic": "and"}],
                "expected_count": 176
            },
            {
                "name": "方向过滤_Long",
                "filters": [{"field": "direction", "operator": "equals", "value": "Long", "logic": "and"}],
                "expected_count": 215
            },
            {
                "name": "净利润_大于0",
                "filters": [{"field": "net_profit", "operator": "greater_than", "value": "0", "logic": "and"}],
                "expected_count": 180
            },
            {
                "name": "净利润_小于0",
                "filters": [{"field": "net_profit", "operator": "less_than", "value": "0", "logic": "and"}],
                "expected_count": 200
            }
        ]
        
        for filter_test in filter_tests:
            self.test_cases.append({
                "name": filter_test["name"],
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": filter_test["filters"],
                "expected_result": {
                    "type": "filter_test",
                    "expected_count": filter_test["expected_count"],
                    "should_have_data": True
                }
            })
        
        # 3. 聚合方式测试
        aggregations = ["sum", "avg", "max", "min", "count"]
        for aggregation in aggregations:
            self.test_cases.append({
                "name": f"聚合_{aggregation}",
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "net_profit",
                "x_aggregation": "count",
                "y_aggregation": aggregation,
                "filters": [],
                "expected_result": {
                    "type": "aggregation_test",
                    "aggregation": aggregation,
                    "should_have_data": True
                }
            })
        
        # 4. X轴字段测试
        x_fields = ["symbol", "direction", "session", "trade_type", "open_date", "weekday"]
        for field in x_fields:
            self.test_cases.append({
                "name": f"X轴字段_{field}",
                "chart_type": "bar",
                "x_field": field,
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": [],
                "expected_result": {
                    "type": "x_field_test",
                    "x_field": field,
                    "should_have_data": True
                }
            })
        
        # 5. Y轴字段测试
        y_fields = ["count", "net_profit", "gross_profit", "win_rate", "profit_factor"]
        for field in y_fields:
            self.test_cases.append({
                "name": f"Y轴字段_{field}",
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": field,
                "x_aggregation": "count",
                "y_aggregation": "sum" if field not in ["count", "win_rate", "profit_factor"] else "count",
                "filters": [],
                "expected_result": {
                    "type": "y_field_test",
                    "y_field": field,
                    "should_have_data": True
                }
            })
        
        # 6. 分段测试
        binning_tests = [
            {
                "name": "分段_固定大小",
                "x_enable_binning": True,
                "x_binning_method": "fixed_size",
                "x_binning_value": 100,
                "x_field": "net_profit"
            },
            {
                "name": "分段_固定数量",
                "x_enable_binning": True,
                "x_binning_method": "fixed_count",
                "x_binning_value": 10,
                "x_field": "net_profit"
            },
            {
                "name": "分段_百分位数",
                "x_enable_binning": True,
                "x_binning_method": "percentile",
                "x_binning_value": 20,
                "x_field": "net_profit"
            }
        ]
        
        for binning_test in binning_tests:
            test_case = {
                "name": binning_test["name"],
                "chart_type": "bar",
                "x_field": binning_test["x_field"],
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": [],
                "expected_result": {
                    "type": "binning_test",
                    "method": binning_test["x_binning_method"],
                    "should_have_data": True
                }
            }
            
            # 添加分段配置
            if binning_test.get("x_enable_binning"):
                test_case["x_enable_binning"] = True
                test_case["x_binning_method"] = binning_test["x_binning_method"]
                test_case["x_binning_value"] = binning_test["x_binning_value"]
                test_case["x_binning_format"] = "range"
                test_case["x_binning_include_empty"] = False
                test_case["x_binning_round_values"] = True
            
            self.test_cases.append(test_case)
        
        # 7. 多过滤器组合测试
        multi_filter_tests = [
            {
                "name": "多过滤器_AND_品种和方向",
                "filters": [
                    {"field": "symbol", "operator": "equals", "value": "MESM25", "logic": "and"},
                    {"field": "direction", "operator": "equals", "value": "Long", "logic": "and"}
                ]
            },
            {
                "name": "多过滤器_OR_两个品种",
                "filters": [
                    {"field": "symbol", "operator": "equals", "value": "MESM25", "logic": "or"},
                    {"field": "symbol", "operator": "equals", "value": "MESU25", "logic": "and"}
                ]
            }
        ]
        
        for multi_test in multi_filter_tests:
            self.test_cases.append({
                "name": multi_test["name"],
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": multi_test["filters"],
                "expected_result": {
                    "type": "multi_filter_test",
                    "should_have_data": True
                }
            })
        
        # 8. 排序测试
        sort_options = ["label_asc", "label_desc", "value_asc", "value_desc", "count_desc"]
        for sort_option in sort_options:
            self.test_cases.append({
                "name": f"排序_{sort_option}",
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": [],
                "x_sort": sort_option,
                "expected_result": {
                    "type": "sort_test",
                    "sort_option": sort_option,
                    "should_have_data": True
                }
            })
        
        # 9. 最大显示数量测试
        max_items_tests = [10, 20, 50, -1]
        for max_items in max_items_tests:
            self.test_cases.append({
                "name": f"最大显示_{max_items}",
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": [],
                "x_max_items": max_items,
                "expected_result": {
                    "type": "max_items_test",
                    "max_items": max_items,
                    "should_have_data": True
                }
            })
        
        # 10. 边界条件测试
        edge_cases = [
            {
                "name": "空值测试_评分",
                "filters": [{"field": "rating", "operator": "is_null", "value": "", "logic": "and"}]
            },
            {
                "name": "非空值测试_评分",
                "filters": [{"field": "rating", "operator": "is_not_null", "value": "", "logic": "and"}]
            },
            {
                "name": "包含测试_品种",
                "filters": [{"field": "symbol", "operator": "contains", "value": "MES", "logic": "and"}]
            },
            {
                "name": "不包含测试_品种",
                "filters": [{"field": "symbol", "operator": "not_contains", "value": "XXX", "logic": "and"}]
            }
        ]
        
        for edge_case in edge_cases:
            self.test_cases.append({
                "name": edge_case["name"],
                "chart_type": "bar",
                "x_field": "symbol",
                "y_field": "count",
                "x_aggregation": "count",
                "y_aggregation": "count",
                "filters": edge_case["filters"],
                "expected_result": {
                    "type": "edge_case_test",
                    "should_have_data": True
                }
            })
        
        print(f"生成了 {len(self.test_cases)} 个核心测试用例")
    
    def run_test_case(self, test_case: Dict) -> Dict:
        """运行单个测试用例"""
        try:
            # 构建请求数据
            request_data = {
                "config": json.dumps(test_case)
            }
            
            # 发送GET请求，配置作为URL参数
            response = requests.get(
                f"{self.base_url}/statistics/chart_data",
                params=request_data,
                timeout=30
            )
            
            # 检查响应
            if response.status_code == 200:
                result_data = response.json()
                
                # 验证结果
                validation_result = self.validate_result(test_case, result_data)
                
                return {
                    "test_case": test_case["name"],
                    "status": "PASS" if validation_result["valid"] else "FAIL",
                    "response_time": response.elapsed.total_seconds(),
                    "data_count": len(result_data.get("trades", [])),
                    "total_trades": result_data.get("total", 0),
                    "validation": validation_result,
                    "details": {
                        "chart_type": test_case.get("chart_type", "N/A"),
                        "x_field": test_case.get("x_field", "N/A"),
                        "y_field": test_case.get("y_field", "N/A"),
                        "filter_count": len(test_case.get("filters", [])),
                        "response_size": len(json.dumps(result_data))
                    }
                }
            else:
                return {
                    "test_case": test_case["name"],
                    "status": "ERROR",
                    "error": f"HTTP {response.status_code}: {response.text[:200]}",
                    "response_time": response.elapsed.total_seconds(),
                    "data_count": 0,
                    "total_trades": 0,
                    "validation": {"valid": False, "message": "HTTP error"},
                    "details": test_case
                }
        
        except Exception as e:
            return {
                "test_case": test_case["name"],
                "status": "ERROR",
                "error": str(e)[:200],
                "response_time": 0,
                "data_count": 0,
                "total_trades": 0,
                "validation": {"valid": False, "message": f"Exception: {str(e)[:100]}"},
                "details": test_case
            }
    
    def validate_result(self, test_case: Dict, result_data: Dict) -> Dict:
        """验证测试结果"""
        expected = test_case["expected_result"]
        
        # 基础验证
        if "trades" not in result_data:
            return {"valid": False, "message": "结果中没有trades字段"}
        
        # 检查数据是否为空
        has_data = len(result_data["trades"]) > 0
        
        if expected["should_have_data"] and not has_data:
            return {"valid": False, "message": "期望有数据但实际为空"}
        
        # 检查特定测试类型
        if expected["type"] == "chart_type_test":
            # 图表类型测试只需要有数据即可
            pass
        elif expected["type"] == "filter_test":
            # 过滤器测试检查数据量
            if "expected_count" in expected:
                total_trades = result_data.get("total", 0)
                if total_trades != expected["expected_count"]:
                    return {"valid": False, "message": f"过滤结果数量不匹配: 期望{expected['expected_count']}, 实际{total_trades}"}
        elif expected["type"] == "aggregation_test":
            # 聚合测试检查数据格式 - 暂时跳过详细验证
            if has_data:
                # 注意：这个API返回的是原始交易数据，不是聚合后的图表数据
                pass
        elif expected["type"] == "max_items_test":
            # 最大显示数量测试 - 暂时跳过，因为这个API返回所有数据
            pass
        
        return {"valid": True, "message": "验证通过"}
    
    def run_all_tests(self):
        """运行所有测试"""
        print(f"开始运行 {len(self.test_cases)} 个测试用例...")
        
        start_time = time.time()
        
        for i, test_case in enumerate(self.test_cases):
            print(f"运行测试 {i+1}/{len(self.test_cases)}: {test_case['name']}")
            
            result = self.run_test_case(test_case)
            self.results.append(result)
            
            # 显示结果
            if result["status"] == "PASS":
                print(f"  ✓ 通过 - {result['data_count']}个数据点, {result['total_trades']}条交易, {result['response_time']:.3f}s")
            elif result["status"] == "FAIL":
                print(f"  ✗ 失败 - {result['validation']['message']}")
            else:
                print(f"  ⚠ 错误 - {result['error']}")
            
            # 短暂延迟
            time.sleep(0.1)
        
        end_time = time.time()
        
        # 生成报告
        self.generate_report(end_time - start_time)
    
    def generate_report(self, total_time: float):
        """生成测试报告"""
        print(f"\n{'='*60}")
        print("专注全面测试报告")
        print(f"{'='*60}")
        
        total_tests = len(self.results)
        passed_tests = sum(1 for r in self.results if r["status"] == "PASS")
        failed_tests = sum(1 for r in self.results if r["status"] == "FAIL")
        error_tests = sum(1 for r in self.results if r["status"] == "ERROR")
        
        print(f"总测试数: {total_tests}")
        print(f"通过: {passed_tests} ({passed_tests/total_tests*100:.1f}%)")
        print(f"失败: {failed_tests} ({failed_tests/total_tests*100:.1f}%)")
        print(f"错误: {error_tests} ({error_tests/total_tests*100:.1f}%)")
        print(f"总耗时: {total_time:.2f}秒")
        
        # 按测试类型统计
        test_types = {}
        for result in self.results:
            test_name = result["test_case"]
            test_type = test_name.split("_")[0]
            if test_type not in test_types:
                test_types[test_type] = {"total": 0, "passed": 0, "failed": 0, "error": 0}
            
            test_types[test_type]["total"] += 1
            if result["status"] == "PASS":
                test_types[test_type]["passed"] += 1
            elif result["status"] == "FAIL":
                test_types[test_type]["failed"] += 1
            else:
                test_types[test_type]["error"] += 1
        
        print(f"\n按测试类型统计:")
        for test_type, stats in test_types.items():
            print(f"  {test_type}: {stats['passed']}/{stats['total']} 通过 ({stats['passed']/stats['total']*100:.1f}%)")
        
        # 显示失败的测试
        if failed_tests > 0:
            print(f"\n失败的测试:")
            for result in self.results:
                if result["status"] == "FAIL":
                    print(f"  - {result['test_case']}: {result['validation']['message']}")
        
        # 显示错误的测试
        if error_tests > 0:
            print(f"\n错误的测试:")
            for result in self.results:
                if result["status"] == "ERROR":
                    print(f"  - {result['test_case']}: {result['error']}")
        
        # 性能统计
        response_times = [r["response_time"] for r in self.results if r["response_time"] > 0]
        if response_times:
            print(f"\n性能统计:")
            print(f"  最快响应: {min(response_times):.3f}秒")
            print(f"  最慢响应: {max(response_times):.3f}秒")
            print(f"  平均响应: {sum(response_times)/len(response_times):.3f}秒")
        
        # 保存详细报告
        self.save_detailed_report()
    
    def save_detailed_report(self):
        """保存详细测试报告"""
        report_data = {
            "timestamp": datetime.now().isoformat(),
            "summary": {
                "total_tests": len(self.results),
                "passed": sum(1 for r in self.results if r["status"] == "PASS"),
                "failed": sum(1 for r in self.results if r["status"] == "FAIL"),
                "errors": sum(1 for r in self.results if r["status"] == "ERROR")
            },
            "test_cases": self.test_cases,
            "results": self.results
        }
        
        with open("focused_comprehensive_test_report.json", "w", encoding="utf-8") as f:
            json.dump(report_data, f, ensure_ascii=False, indent=2)
        
        print(f"\n详细报告已保存到: focused_comprehensive_test_report.json")


def main():
    """主函数"""
    print("启动专注的全面测试套件...")
    
    tester = FocusedComprehensiveTest()
    
    # 生成测试用例
    tester.generate_core_test_cases()
    
    # 运行测试
    tester.run_all_tests()
    
    print("\n专注全面测试完成!")


if __name__ == "__main__":
    main() 